<?php if(!defined('SPRITCH')) { exit(); }

// Spritch - An opensource PHP5 web framework

// Author: Luca Degasperi
// Licence: GNU GPL
// Site: http://www.spritch.org/

// Class: Profiler
// Summary: This class provides profiling functions
// Since: 0.9.1

final class profiler extends spritch
{
	private $crono = array();
	private $count = array('log' => 0,'error' => 0,'warning' => 0,'memory' => 0,'query' => 0,'speed' => 0,'include' => 0);
	private $benchmarks = array();
	private $system_data = array();
	
	public function __construct()
	{
		$this->log('profiler class started');
	}
	
	private function add($array)
	{
		$this->crono[] = $array;
		$this->count[$array['type']]++;
	}
	
	private function convert_time($time)
	{
		$formats = array('ms','s','m');
		$i = 0;		
		if($time >= 1000 and $time < 60000)
		{
			$i = 1;
			$time = ($time/1000);
		}
		else if($time >= 60000)
		{
			$i = 2;
			$time = ($time/1000)/60;
		}
		$time = number_format($time,3,'.','').' '.$formats[$i];
		return $time;
	}
	
	private function convert_memory($value,$return = false)
	{
		$sizes = array('B','kB','MB','GB','TB');
		if(!$return)
			$return = '%01.2f %s';
		$lastsize = end($sizes);
		foreach($sizes as $sizestring)
		{
			if($value < 1024)
				break;
			if($sizestring != $lastsize)
				$value /= 1024;
		}
		if($sizestring == $sizes[0])
			$return = '%01d %s';
	    return sprintf($return,$value,$sizestring);
	}
	
	private function included_files()
	{
		$files = get_included_files();
		$sizes = 0;
		foreach($files as $file)
		{
			$size = filesize($file);
			$sizes += $size;
			$data = array('type' => 'include','message' => $file,'data' => $this->convert_memory($size));
			$this->add($data);
		}
		return $this->convert_memory($sizes);
	}
	
	private function gather_data()
	{
		$this->system_data['time_used'] = $this->benchmark('system');
		$this->system_data['time_limit'] = ini_get('max_execution_time').' s';
		$this->system_data['memory_used'] = $this->convert_memory(memory_get_peak_usage());
		$this->system_data['memory_limit'] = $this->convert_memory(ini_get('memory_limit')*1000000);		
		$this->system_data['included_files_size'] = $this->included_files();
	}
	
	public function log($message)
	{
		$data = array('type' => 'log','message' => $message);
		$this->add($data);
	}
	
	public function error($message,$info = array())
	{
		$data = array('type' => 'error','message' => $message,'file' => isset($info['file'])?$info['file']:'','line' => isset($info['line'])?$info['line']:'');
		$this->add($data);
	}
	
	public function warning($message)
	{
		$data = array('type' => 'warning','message' => $message);
		$this->add($data);
	}
	
	public function memory($message = 'Memory',$object = false)
	{
		$memory = memory_get_usage();
		if($object)
			$memory = strlen(serialize($object));
		$data = array('type' => 'memory','message' => $message,'data' => $this->convert_memory($memory),'datatype' => gettype($object));
		$this->add($data);
		return $data['data'];
	}
	
	public function query($message)
	{
		$data = array('type' => 'query','message' => $message);
		$this->add($data);
	}
	
	public function benchmark($name)
	{
		if(array_key_exists($name,$this->benchmarks) and $this->benchmarks[$name]['stop'] === false)
		{
			$this->benchmarks[$name]['stop'] = microtime();
			$data = array('type' => 'speed','message' => $name,
				'data' => $this->convert_time(($this->benchmarks[$name]['stop'] - $this->benchmarks[$name]['start']) * 1000));
			$this->add($data);
			return $data['data'];
		}
		else
			$this->benchmarks[$name] = array('start' => microtime(),'stop' => false);	
	}
	
	public function get($priority = false)
	{
		if(!$priority)
			return $this->crono;
		else
			if(array_key_exists($priority,$this->logs))
				return $this->logs[$priority];
	}
	
	public function render()
	{
		$this->log('profiler rendering');
		$this->gather_data();
		?>
		<style type="text/css">
		#profiler{position:absolute;width:100%;top:0;left:0;z-index:999;margin:0;color:#FFFFFF;font-family: "Bitstream Vera Sans Mono", monospace;font-size: 1.1em;}
		#profiler_content{height:150px;overflow:scroll;position:relative;z-index:3;display:none;background:#222;}
		#profiler_tab{float:right;width:120px;position:relative;top:0;right:0;z-index:999;background:#222;right:0;padding:5px;text-align:center;}
		#profiler_content td,th{padding-left: 10px;padding-right: 10px;}
		</style>
		<script type="text/javascript">
			function sh_profiler() { var status = document.getElementById('profiler_content'); var tab = document.getElementById('profiler_tab');
				if(status.style.display == '' || status.style.display == 'none') {status.style.display = 'block'; tab.innerHTML = 'Hide Profiler';}
				else { status.style.display = 'none'; tab.innerHTML = 'Show Profiler';}}
		</script>
		<div id="profiler"><div id="profiler_content"><table cellpadding="0" cellspacing="0" border="0" style="color:#FFFFFF; margin: 10px;">
				<?php
					foreach($this->crono as $arr)
						if($arr['type'] != 'include')
						echo '<tr><td>'.$arr['type'].'</td><td>'.$arr['message'].'</td><td>'.$arr['priority'].'</td><td>'.$arr['data'].'</td></tr>';
					/*echo '<tr><td>benchmark.php</td><td></td><td>debug</td><td>system benchmark ended in: '.$this->benchmark->get('system').'s memory used: '.$this->benchmark->get_usage('system').'B</td></tr>';*/
				?>
			</table></div>
			<div id="profiler_tab" onclick="sh_profiler()">Show Profiler</div>
		</div>
		<?
	}
}
?>